package com.zlk.algorithm.dataStructure.tree.treeDp;

import cn.hutool.core.lang.tree.Tree;
import com.zlk.algorithm.dataStructure.tree.TreeNode;
import org.junit.Test;

/**
 * @program: algorithm
 * @ClassName IsFull
 * @description:是否是满二叉树
 * @author: slfang
 * @create: 2024-02-19 15:53
 * @Version 1.0
 **/
public class IsFull {



    class Info{
        int height;
        int nodes;

        public Info(int height,int nodes){
            this.height = height;
            this.nodes = nodes;
        }
    }

    // 第一种方法
    // 收集整棵树的高度h，和节点数n
    // 只有满二叉树满足 : 2 ^ h - 1 == n
    public boolean showProcess(TreeNode node){
        Info all = process(node);
        return (1 << all.height) - 1 == all.nodes;
    }

    public Info process(TreeNode node){
        //base case
        if(node==null){
            return new Info(0,0);
        }
        Info leftInfo = process(node.left);
        Info rightInfo = process(node.right);
        int height = Math.max(leftInfo.height, rightInfo.height) + 1;
        int nodes = leftInfo.nodes + rightInfo.nodes + 1;
        return new Info(height, nodes);
    }

    // for test
    public static TreeNode generateRandomBST(int maxLevel, int maxValue) {
        return generate(1, maxLevel, maxValue);
    }

    // for test
    public static TreeNode generate(int level, int maxLevel, int maxValue) {
        if (level > maxLevel || Math.random() < 0.5) {
            return null;
        }
        TreeNode head = new TreeNode((int) (Math.random() * maxValue));
        head.left = generate(level + 1, maxLevel, maxValue);
        head.right = generate(level + 1, maxLevel, maxValue);
        return head;
    }


    // 第二种方法
    // 收集子树是否是满二叉树
    // 收集子树的高度
    // 左树满 && 右树满 && 左右树高度一样 -> 整棵树是满的
    public static boolean isFull2(TreeNode head) {
        if (head == null) {
            return true;
        }
        return process2(head).isFull;
    }
    public static class Info2 {
        public boolean isFull;
        public int height;

        public Info2(boolean f, int h) {
            isFull = f;
            height = h;
        }
    }

    public static Info2 process2(TreeNode h) {
        if (h == null) {
            return new Info2(true, 0);
        }
        Info2 leftInfo = process2(h.left);
        Info2 rightInfo = process2(h.right);
        boolean isFull = leftInfo.isFull && rightInfo.isFull && leftInfo.height == rightInfo.height;
        int height = Math.max(leftInfo.height, rightInfo.height) + 1;
        return new Info2(isFull, height);
    }
    @Test
    public void test(){
        int maxLevel = 5;
        int maxValue = 100;
        int testTimes = 1000000;
        System.out.println("测试开始");
        for (int i = 0; i < testTimes; i++) {
            TreeNode head = generateRandomBST(maxLevel, maxValue);
            if (isFull2(head) != showProcess(head)) {
                System.out.println("出错了!");
            }
        }
        System.out.println("测试结束");

    }


}
